//
//  FGMessagesViewController.m
//  FGChatKit
//
//  Created by Henry on 2021/5/8.
//

#import "FGMessagesViewController.h"
#import "UIView+FGLayout.h"

#import "FGVoiceAnimationView.h"
#import "FGChatHelper.h"
#import "FGChatConfiguration.h"
#import "FGResources.h"
#import "FGMessagesViewController+UIMenu.h"
#import "UIView+FGFrame.h"
#import "NSDate+FGTime.h"
#import "UIImage+FGCompress.h"
#import "FGPathTool.h"
#import "FGAudioRecorder.h"

#import "FGMessageWebViewController.h"

@interface FGMessagesViewController () <FGKeyboardViewDelegate, FGMessageCellDelegate, FGNoticeViewDelegate, UIGestureRecognizerDelegate>

@property (nonatomic, strong) FGVoiceAnimationView *voiceView;

@property (nonatomic, strong) NSMutableArray *heightCache;

@property (nonatomic, strong) UIActivityIndicatorView *indicatorView;

/// 记录最新展示的时间消息
@property (nonatomic, strong) FGMessageCellData *msgForDate;
/// 记录最新的消息
@property (nonatomic, strong) FGMessageCellData *msgForGet;

/// 菜单数据
@property (nonatomic, strong, nullable) FGMessageCellData *menuMsg;
/// 重发数据
@property (nonatomic, strong) FGMessageCellData *reSendMsg;


@property (nonatomic, assign) BOOL isScrollBottom;
@property (nonatomic, assign) BOOL isLoadingMsg;
@property (nonatomic, assign) BOOL noMoreMsg;
@property (nonatomic, assign) BOOL firstLoad;

@end

@implementation FGMessagesViewController

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self defaultValue];
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    if (!self.conversationId) {
        NSAssert(NO, @"必须设置conversationId，方便管理会话文件");
    }
    
    self.view.backgroundColor = [FGChatConfiguration shareInstance].backgroundColor;
    
    _firstLoad = YES;

    [self setupViews];
    [self registerCell];
    [self loadMessage];

}

- (void)defaultValue {
    _messageTimeInterval = 5 * 60;

}

- (void)setupViews {
    [self.view addSubview:self.tableView];
    [self.view addSubview:self.keyboardView];
    [self _updateTableViewFormKeyboard];

    _heightCache = [NSMutableArray array];
    _dataArray = [NSMutableArray array];
    _firstLoad = YES;
    
//    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapViewController)];
//    tap.delegate = self;
//    [self.tableView addGestureRecognizer:tap];

}

- (void)didTapViewController {
    [self hiddenKeyboard];
}

- (void)registerCell {
    [FGTextMessageCellData registerCellToTableView:self.tableView];
    [FGSystemMessageCellData registerCellToTableView:self.tableView];
    [FGImageMessageCellData registerCellToTableView:self.tableView];
    [FGVoiceMessageCellData registerCellToTableView:self.tableView];
    [FGVideoMessageCellData registerCellToTableView:self.tableView];
    [FGFaceMessageCellData registerCellToTableView:self.tableView];
    [FGFileMessageCellData registerCellToTableView:self.tableView];
    [FGTemplateMessageCellData registerCellToTableView:self.tableView];
}

#pragma mark - loadMessage

- (void)loadMessage {
    if (_isLoadingMsg || _noMoreMsg) {
        return;
    }
    _isLoadingMsg = YES;
    int msgCount = 20;

//    @weakify(self)
    [self loadMessage:self.msgForGet complation:^(BOOL status, NSArray *msgs) {
//        @strongify(self)
        
        if (msgs.count != 0) {
            self.msgForGet = msgs[0];
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
                   
            if (msgs.count < msgCount) {
                self.noMoreMsg = YES;
                self.indicatorView.mm_h = 0;
            }
            
            if (msgs.count != 0) {
                NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, msgs.count)];
                [self.dataArray insertObjects:msgs atIndexes:indexSet];
                [self.heightCache removeAllObjects];
                [self.tableView reloadData];
                [self.tableView layoutIfNeeded];

                if (!self.firstLoad) {
                    CGFloat visibleHeight = 0;
                    for (NSInteger i = 0; i < msgs.count; ++i) {
                        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
                        visibleHeight += [self tableView:self.tableView heightForRowAtIndexPath:indexPath];
                    }
                    visibleHeight -= self.tableView.contentInset.bottom;
                    if (self.noMoreMsg) {
                        visibleHeight -= 40;
                    }
                    [self.tableView scrollRectToVisible:CGRectMake(0, self.tableView.contentOffset.y + visibleHeight, self.tableView.frame.size.width, self.tableView.frame.size.height) animated:NO];
                }
            }
            
            self.isLoadingMsg = NO;
            [self.indicatorView stopAnimating];
            self.firstLoad = NO;
                        
        });
        
    }];
    
}

#pragma mark - Public Set

- (void)loadMessage:(FGMessageCellData *)msg complation:(void (^)(BOOL, NSArray * _Nonnull))complation {}

- (void)sendMessage:(FGMessageCellData *)msg complation:(void (^)(BOOL, FGMessageCellData * _Nonnull))complation {}

- (void)setMoreItem:(NSMutableArray<FGKeyboardMoreItem *> *)items {
    [self.keyboardView setMoreItems:items];
}

#pragma mark - Public Methods

- (void)configLayout:(CGSize)size {
    [self.keyboardView configLayout:size];
    self.tableView.size = size;
    self.indicatorView.width = size.width;
}

- (void)hiddenKeyboard {
    [self.keyboardView dismissKeyboard];
}

- (BOOL)showTimeFrom:(NSString *)time {
    if (!_msgForDate) {
        return YES;
    }
    NSDate *date = [NSDate date:time];
    NSDate *msgDate = [NSDate date:_msgForDate.time];
    if (fabs([date timeIntervalSinceDate:msgDate]) > _messageTimeInterval) {
        return YES;
    }
    return NO;
}

- (void)showMessageTimeWithData:(FGMessageCellData *)data {
    BOOL showTime = [self showTimeFrom:data.time];
    if (showTime) {
        _msgForDate = data;
    }
    data.showTime = showTime;
}

- (void)changeMsg:(FGMessageCellData *)msg status:(FGMsgStatus)status {
    msg.status = status;
    NSInteger index = [_dataArray indexOfObject:msg];
    FGMessageCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]];
    [cell fillWithData:msg];
}

- (NSIndexPath *)indexPathOfMsg:(FGMessageCellData *)msg {
    return [self indexPathOfMsgId:msg.msgId];
}

- (NSIndexPath *)indexPathOfMsgId:(NSString *)msgId {
    NSInteger index = -1;
    for (NSInteger i = self.dataArray.count-1; i < self.dataArray.count; i --) {
        FGMessageCellData *data = self.dataArray[i];
        if ([data.msgId isEqualToString:msgId]) {
            index = i;
            break;
        }
    }
    return [NSIndexPath indexPathForRow:index inSection:0];
}

- (FGMessageCellData *)dataOfUUID:(NSString *)uuid {
    for (NSInteger i = self.dataArray.count-1; i < self.dataArray.count; i --) {
        FGMessageCellData *data = self.dataArray[i];
        if ([data.uuid isEqualToString:uuid]) {
            return data;
        }
    }
    return nil;
}

- (void)scrollToBottom:(BOOL)animate {
    if (_dataArray.count > 0) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.dataArray.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animate];
        });
    }
}

- (void)updateTableViewTopInset:(CGFloat)top {
    UIEdgeInsets insets = self.tableView.contentInset;
    insets.top = top;
    self.tableView.contentInset = insets;
    self.tableView.scrollIndicatorInsets = insets;
}

- (void)updateTableViewBottomInset:(CGFloat)bottom {
    UIEdgeInsets insets = self.tableView.contentInset;
    insets.bottom = bottom;
    self.tableView.contentInset = insets;
    self.tableView.scrollIndicatorInsets = insets;
}

- (void)acceptMessages:(NSArray<FGMessageCellData *> *)msgs {
    [self.tableView beginUpdates];
    for (FGMessageCell *data in msgs) {
        [self.dataArray addObject:data];
        [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.dataArray.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
    }
    [self.tableView endUpdates];
}

- (void)sendMessage:(FGMessageCellData *)msg {
    if (!self.conversationId) {
        NSAssert(NO, @"必须设置conversationId，方便管理会话文件");
    }
    
    msg.conversationId = self.conversationId;

    if (msg.status == FGMsgStatusFail) {
        // 重发
        NSInteger row = [_dataArray indexOfObject:msg];
        [_heightCache removeObjectAtIndex:row];
        [_dataArray removeObjectAtIndex:row];
        [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:row inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
    }

    msg.name = [FGChatConfiguration shareInstance].loginName;
    msg.sender = [[FGChatConfiguration shareInstance] loginId];
    msg.status = FGMsgStatusSending;
    msg.time = [NSDate timestamp:[NSDate date]];
    [self showMessageTimeWithData:msg];

    // 添加到列表
    [_dataArray addObject:msg];
    [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:_dataArray.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
    [self scrollToBottom:YES];
    
    __weak typeof(self) ws = self;
    dispatch_async(dispatch_get_main_queue(), ^{
        if (msg.status == FGMsgStatusSending) {
            [ws changeMsg:msg status:FGMsgStatusSending];
        }
    });
    
    [self sendMessage:msg complation:^(BOOL status, FGMessageCellData * _Nonnull msg) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [ws changeMsg:msg status:status?FGMsgStatusSucc:FGMsgStatusFail];
        });
    }];
}

- (void)sendMessageText:(NSString *)text {
    // 去掉前后空格
    text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    if (text.length == 0) return;
    FGTextMessageCellData *data = [[FGTextMessageCellData alloc] initWithDirection:FGMsgDirectionOutgoing];
    data.content = text;
    [self sendMessage:data];
}

- (void)sendMessageSystem:(NSString *)system {
    FGSystemMessageCellData *data = [[FGSystemMessageCellData alloc] init];
    data.content = system;
    [self sendMessage:data];
}

- (void)sendMessageImage:(UIImage *)image {
    if (!image) {
//        [FGToastTool show:@"请选择有效的图片"];
        // TODO
        return;
    }
    
    CGFloat maxImageLength = [FGChatConfiguration shareInstance].maxImageLength;
    CGFloat maxImageWidth = [FGChatConfiguration shareInstance].maxImageWidth;

    if (maxImageLength > 0) {
        NSData *imageData = [UIImage fg_compressImage:image toMaxLength:maxImageLength*1024*1024 maxWidth:maxImageWidth];
        image = [UIImage imageWithData:imageData];
    }
    NSData *imgData = UIImagePNGRepresentation(image);
    CGSize size = image.size;
    CGSize thumbSize = [FGChatHelper getThumbSizeFromOrigin:size];
    UIImage *thumbImage = [UIImage fg_resizeImage:image scaleToSize:thumbSize];
    
    NSString *uuid = [FGChatHelper generateUUID];
    NSString *imagePath = [FGChatHelper pathConvImage:self.conversationId name:uuid];
    
    NSString *thumbPath = [FGChatHelper pathConvImage:self.conversationId name:[NSString stringWithFormat:@"%@_thumb", uuid]];

    [[NSFileManager defaultManager] createFileAtPath:imagePath contents:imgData attributes:nil];
    [[NSFileManager defaultManager] createFileAtPath:thumbPath contents:UIImagePNGRepresentation(thumbImage) attributes:nil];

    FGImageMessageCellData *data = [[FGImageMessageCellData alloc] initWithDirection:FGMsgDirectionOutgoing];
    data.uuid = uuid;
    data.thumbImage = thumbImage;
    data.path = imagePath;

    NSMutableArray *items = [NSMutableArray array];
    // 缩略图
    FGImageItem *thumbItem = [[FGImageItem alloc] init];
    thumbItem.type = FGImageTypeThumb;
    thumbItem.size = [FGChatHelper getThumbSizeFromOrigin:size];
    [items addObject:thumbItem];
    // 原图
    FGImageItem *originItem = [[FGImageItem alloc] init];
    originItem.type = FGImageTypeOrigin;
    originItem.size = size;
    [items addObject:originItem];
    data.items = items;

    [self sendMessage:data];
}

// {path, duration} path:路径 duration:长度(秒)
- (void)sendMessageVoice:(NSDictionary *)voice {
    int duration = [voice[@"duration"] intValue];
    NSString *path = voice[@"path"];
    if (!path || duration < 1) {
//        [FGToastTool show:GetHCLocalizableString(@"InputRecordTimeshort")];
        // TODO
        return;
    }
    
    // 上传语音
    int length = (int)[[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize];
    
    NSString *uuid = [[path stringByDeletingPathExtension] lastPathComponent];
    NSString *ext = [path pathExtension];
    
    NSString *chatPath = [FGChatHelper pathConvVoice:self.conversationId name:path.lastPathComponent];
    // 移动文件
    [self moveSourceFile:path desPath:chatPath];
    
    FGVoiceMessageCellData *data = [[FGVoiceMessageCellData alloc] initWithDirection:FGMsgDirectionOutgoing];
    data.uuid = uuid;
    data.type = ext;
    data.path = chatPath;
    data.duration = duration;
    data.length = length;
    data.url = voice[@"url"] ?:@"";
    
    [self sendMessage:data];
}

- (void)moveSourceFile:(NSString *)path desPath:(NSString *)desPath {
    
    [FGPathTool moveSourceFile:path toDesPath:desPath];
    
    NSInteger lastSize = 0;
    NSDictionary *fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:desPath error:nil];
    NSInteger fileSize = [[fileAttrs objectForKey:NSFileSize] intValue];
    do {
          lastSize = fileSize;
          fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:desPath error:nil];
          fileSize = [[fileAttrs objectForKey:NSFileSize] intValue];
     } while (lastSize != fileSize);
     
}

#pragma mark - Private Methods

- (void)_updateTableViewFormKeyboard {
    const CGFloat bottom = CGRectGetMaxY(self.view.frame) - CGRectGetMinY(self.keyboardView.frame) - [FGChatHelper bottomSafeHeight];
    [self updateTableViewBottomInset:bottom];
}


#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (!_noMoreMsg && scrollView.contentOffset.y <= 40) {
        if (!_indicatorView.isAnimating) {
            [_indicatorView startAnimating];
        }
    } else {
        if (_indicatorView.isAnimating) {
            [_indicatorView stopAnimating];
        }
    }

    // TODO 为了点击状态栏到顶部  self.navigationController.navigationBar.translucent 有关系
    
    if (self.navigationController.navigationBar.translucent) {
        if (scrollView.contentOffset.y == -100) {
            [self loadMessage];
        }
    } else {
        if (scrollView.contentOffset.y == 0) {
            [self loadMessage];
        }
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    if (scrollView.contentOffset.y <= 40) {
        [self loadMessage];
    }
}

#pragma mark - UITableViewDataSource

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (_isScrollBottom == NO) {
        [self scrollToBottom:NO];
        if (indexPath.row == _dataArray.count-1) {
            _isScrollBottom = YES;
        }
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    FGMessageCellData *data = _dataArray[indexPath.row];
    
    FGMessageCell *cell = [data dequeueCellByTableView:tableView indexPath:indexPath];
    cell.delegate = self;
    [cell fillWithData:_dataArray[indexPath.row]];

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat height = 0;
    if (self.heightCache.count > indexPath.row) {
        return [self.heightCache[indexPath.row] floatValue];
    }
    FGMessageCellData *data = self.dataArray[indexPath.row];
    height = [data heightOfWidth:[UIScreen mainScreen].bounds.size.width];
    [self.heightCache insertObject:[NSNumber numberWithFloat:height] atIndex:indexPath.row];
    return height;
}

#pragma mark - FGMessageCellDelegate

/// 点击了模板消息上的Cell
- (void)didSelectedTemplateMessageCell:(NSDictionary *)templateDict
{
    if ([self.delegate respondsToSelector:@selector(messageController:didSelectedTemplateMessageCell:)]) {
        [self.delegate messageController:self didSelectedTemplateMessageCell:templateDict];
    }
}

/// 表单提交
- (void)fromSubmit:(NSArray *)fromArr
{
    if ([self.delegate respondsToSelector:@selector(messageController:submitFrom:)]) {
        [self.delegate messageController:self submitFrom:fromArr];
    }
}

/// 图片下载完成
- (void)imageDownloadComplete:(FGMessageCell *)cell
{
//    [self changeMsg:cell.messageData status:cell.messageData.status];
    NSInteger row = [self indexPathOfMsg:cell.messageData].row;
    [self.heightCache removeObjectAtIndex:row];
    CGFloat height = [cell.messageData heightOfWidth:[UIScreen mainScreen].bounds.size.width];
    [self.heightCache insertObject:[NSNumber numberWithFloat:height] atIndex:row];
    [self.tableView reloadData];
    
    if ([self.delegate respondsToSelector:@selector(messageController:imageDownloadComplete:)]) {
       [self.delegate messageController:self imageDownloadComplete:cell];
    }
}

- (void)onRetryMessage:(FGMessageCell *)cell {
    _reSendMsg = cell.messageData;
//    [FGAlertTool alertWithTitle:GetHCLocalizableString(@"TipsConfirmResendMessage") message:nil cancelTitle:GetHCLocalizableString(@"Cancel") buttonTitles:@[GetHCLocalizableString(@"Re-send")] actionsBlock:^(NSInteger buttonIndex, NSString * _Nonnull buttonTitle) {
//        if (buttonIndex == 0) {
//            [self sendMessage:self.reSendMsg];
//        }
//    }];
    // TODO
}

- (void)onSelectMessageAvatar:(FGMessageCell *)cell {
    if ([self.delegate respondsToSelector:@selector(messageController:onSelectMessageAvatar:)]) {
       [self.delegate messageController:self onSelectMessageAvatar:cell];
    }
}

- (void)onSelectMessage:(FGMessageCell *)cell {
    [self hiddenKeyboard];
    if ([cell isKindOfClass:[FGVoiceMessageCell class]]) {
        [self playVoiceMessage:(FGVoiceMessageCell *)cell];
    }
    if ([cell isKindOfClass:[FGImageMessageCell class]]) {
        [self showImageMessage:(FGImageMessageCell *)cell];
    }
    if ([cell isKindOfClass:[FGVideoMessageCell class]]) {
        [self showVideoMessage:(FGVideoMessageCell *)cell];
    }
    if ([cell isKindOfClass:[FGFileMessageCell class]]) {
        [self showFileMessage:(FGFileMessageCell *)cell];
    }
    if ([cell isKindOfClass:[FGTemplateMessageCell class]]) {
        [self showTemplateMessage:(FGTemplateMessageCell *)cell];
    }
    
    if ([self.delegate respondsToSelector:@selector(messageController:onSelectMessageContent:)]) {
        [self.delegate messageController:self onSelectMessageContent:cell];
    }
}

- (void)onLongPressMessage:(FGMessageCell *)cell {
    FGMessageCellData *data = cell.messageData;
    if ([data isKindOfClass:[FGSystemMessageCellData class]])
        return; // 系统消息不响应
    
    if (_delegate && [_delegate respondsToSelector:@selector(messageController:willShowMenuInCell:)]) {
        BOOL show = [_delegate messageController:self willShowMenuInCell:cell];
        if (!show) {
            return;
        }
    }
        
    NSMutableArray *items = [NSMutableArray array];
    if ([data isKindOfClass:[FGTextMessageCellData class]]) {
        [items addObject:HCLocalizableString(Copy)];
    }
    if (data.status == FGMsgStatusFail) {
        [items addObject:HCLocalizableString(Re-send)];
    }
    
    if (_delegate && [_delegate respondsToSelector:@selector(messageController:menuItemIncell:)]) {
        NSArray *arr = [_delegate messageController:self menuItemIncell:cell];
        [items addObjectsFromArray:arr];
    }
    
    if (items.count == 0) {
        return;
    }
    
    _menuMsg = data;

    __weak typeof(self) ws = self;
    [self showSelectWithMenus:items inView:cell.container clickMenuCompletion:^(NSString * _Nonnull menuTitle, FGMessagesViewController * _Nonnull controller) {
        if ([menuTitle isEqualToString:HCLocalizableString(Copy)]) {
            [self onCopyMsg];
        } else if ([menuTitle isEqualToString:HCLocalizableString(Re-send)]) {
            [self onReSend];
        }
        [ws onClickMenu:menuTitle];
    }];

}

- (void)onClickMenu:(NSString *)menuTitle {
    if (_delegate && [_delegate respondsToSelector:@selector(messageController:onSelectMenu:msg:)]) {
        [_delegate messageController:self onSelectMenu:menuTitle msg:_menuMsg];
    }
    _menuMsg = nil;
}

- (void)onDelete {
    [self.tableView beginUpdates];
    NSInteger index = [self.dataArray indexOfObject:self.menuMsg];
    [self.dataArray removeObjectAtIndex:index];
    [self.heightCache removeObjectAtIndex:index];
    [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
}

- (void)onRevoke:(NSString *)text {
    [self onRevoke:text msgId:self.menuMsg.msgId];
}

- (void)onRevoke:(NSString *)text msgId:(NSString *)msgId {
    if (!msgId || msgId.length == 0) {
        return;
    }
    NSIndexPath *indexPath =  [self indexPathOfMsgId:msgId];
    if (indexPath.row < 0 || indexPath.row > self.dataArray.count) {
        return;
    }

    [self.tableView beginUpdates];
    NSUInteger index = indexPath.row;
    [self.dataArray removeObjectAtIndex:index];
    [self.heightCache removeObjectAtIndex:index];
    [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
    
    FGSystemMessageCellData *data = [[FGSystemMessageCellData alloc] initWithDirection:self.menuMsg.direction];
    data.time = self.menuMsg.time;
    data.showTime = self.menuMsg.showTime;
    data.sender = self.menuMsg.sender;
    if (text && text.length > 0) {
        data.content = text;
    } else {
        data.content = GetHCLocalizableString(@"MessageTipsYouRecallMessage");
    }
    CGFloat height = [data heightOfWidth:[UIScreen mainScreen].bounds.size.width];
    
    [self.dataArray insertObject:data atIndex:index];
    [self.heightCache insertObject:[NSNumber numberWithFloat:height] atIndex:index];

    [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
}

- (void)onReSend {
    [self sendMessage:_menuMsg];
}

- (void)onCopyMsg {
    if ([_menuMsg isKindOfClass:[FGTextMessageCellData class]]) {
        FGTextMessageCellData *textMsg = (FGTextMessageCellData *)_menuMsg;
        UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
        pasteboard.string = textMsg.content;
    }
}

- (void)playVoiceMessage:(FGVoiceMessageCell *)cell {
    for (NSInteger index = 0; index < self.dataArray.count; ++index) {
        if(![self.dataArray[index] isKindOfClass:[FGVoiceMessageCellData class]]){
            continue;
        }
        FGVoiceMessageCellData *data = self.dataArray[index];
        if (data == cell.voiceData) {
            [data playVoiceMessage];
        } else {
            [data stopVoiceMessage];
        }
    }
}

- (void)showImageMessage:(FGImageMessageCell *)cell {
//    [FGPhotoTool showImageWithController:self source:@[[cell.imageData getPreviewImage]] previews:@[cell.thumbView] index:0];
    // TODO
}

- (void)showVideoMessage:(FGVideoMessageCell *)cell {
//    NSURL *url = [NSURL URLWithString:cell.videoData.videoItem.url];
//    NSURL *converUrl = [NSURL URLWithString:cell.videoData.snapshotItem.url];
//    [FGPhotoTool showVideoWithController:self videoURL:url coverURL:converUrl videoDuration:cell.videoData.videoItem.duration preview:cell.thumbView];
    // TODO
}

- (void)showFileMessage:(FGFileMessageCell *)cell {
    
}

// 点击了模板消息（商品、活动、表单）
- (void)showTemplateMessage:(FGTemplateMessageCell *)cell {
    NSDictionary *data = cell.templateData.templateData;
    NSInteger type = [data[@"type"] integerValue];
    if (type != /* DISABLES CODE */ (3) || type != 4) {
        return;
    }
    NSString *url = [data valueForKeyPath:@"data.linkUrl"];
    if (!url) {
        return;
    }
    
    FGMessageWebViewController *vc = [FGMessageWebViewController new];
    vc.url = url;
    [self.navigationController pushViewController:vc animated:YES];
}

#pragma mark - FGKeyboardViewDelegate

- (void)keyboard:(FGKeyboardView *)keyboard didChangeHeight:(CGFloat)height {
    [self _updateTableViewFormKeyboard];
    [self scrollToBottom:YES];
}

- (void)keyboard:(FGKeyboardView *)keyboard didSelectMoreItem:(FGKeyboardMoreItem *)moreItem {
    if (self.delegate && [self.delegate respondsToSelector:@selector(messageController:onSelectMoreItem:)]) {
        [self.delegate messageController:self onSelectMoreItem:moreItem];
    }
}

- (void)keyboard:(FGKeyboardView *)keyboard didDeleteAt:(NSString *)text {
    
}

- (void)keyboardDidInputAt:(FGKeyboardView *)keyboard {
    
}

- (void)keyboard:(FGKeyboardView *)keyboard voiceState:(FGKeyboardVoiceState)state {
    switch (state) {
        case FGKeyboardVoiceNormal:
        {
            [self.voiceView show];
            self.voiceView.state = FGVoiceNormal;
            [[FGAudioRecorder shared] startRecord];
        }
            break;
        case FGKeyboardVoiceWillCancel:
        {
            self.voiceView.state = FGVoiceWillCancel;
        }
            break;
        case FGKeyboardVoiceContinue:
        {
            self.voiceView.state = FGVoiceNormal;
        }
            break;
        case FGKeyboardVoiceCancel:
        {
            self.voiceView.state = FGVoiceCancel;
            [self.voiceView dismiss];
            [[FGAudioRecorder shared] cancelRecording];
        }
            break;
        case FGKeyboardVoiceFinished:
        {
            [self voiceFinished];
        }
            break;
            
        default:
            break;
    }
}

- (void)keyboard:(FGKeyboardView *)keyboard sendText:(NSString *)text {
    NSLog(@"%@", text);
    [self sendMessageText:text];
}

- (void)voiceFinished {
    self.voiceView.state = FGVoiceFinished;
    [self.voiceView dismiss];
    NSDictionary *recordInfo = [FGAudioRecorder.shared stopRecord];
    NSLog(@"recordInfo: %@", recordInfo);
    [self sendMessageVoice:recordInfo];
}

#pragma mark - FGNoticeViewDelegate

- (void)noticeView:(FGNoticeView *)view updateHeight:(CGFloat)height {
    [self updateTableViewTopInset:height];
}

- (void)noticeView:(FGNoticeView *)view clickTitle:(NSString *)title {
    if (self.delegate && [self.delegate respondsToSelector:@selector(messageController:noticeView:clickTitle:)]) {
        [self.delegate messageController:self noticeView:view clickTitle:title];
    }
}


#pragma mark - Layout

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.tableView.frame = self.view.bounds;
}

#pragma mark - Getters

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
        _tableView.dataSource = self;
        _tableView.delegate = self;
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        _tableView.estimatedRowHeight = 0;
        _tableView.estimatedSectionHeaderHeight = 0;
        _tableView.estimatedSectionFooterHeight = 0;
        _tableView.backgroundColor = self.view.backgroundColor;
        _tableView.tableHeaderView = self.indicatorView;
        _tableView.tableFooterView = [[UIView alloc] init];
    }
    return _tableView;
}

- (UIActivityIndicatorView *)indicatorView {
    if (!_indicatorView) {
        _indicatorView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 40)];
    }
    return _indicatorView;
}

- (FGKeyboardView *)keyboardView {
    if (!_keyboardView) {
        _keyboardView = [[FGKeyboardView alloc] init];
        _keyboardView.delegate = self;
        // 文本最大长度
        _keyboardView.maxLength = 1000;
        FGKeyboardConfiguration *configuration = [[FGKeyboardConfiguration alloc] init];
        configuration.recordTitle = GetHCLocalizableString(@"InputHoldToTalk");
        configuration.recordHLTitle = GetHCLocalizableString(@"InputReleaseToSend");
        [_keyboardView configLayout:self.view.frame.size];
        _keyboardView.configuration = configuration;
    }
    return _keyboardView;
}

- (FGNoticeView *)noticeView {
    if (!_noticeView) {
        _noticeView = [[FGNoticeView alloc] init];
        _noticeView.delegate = self;
        _noticeView.hidden = YES;
    }
    return _noticeView;
}

- (FGVoiceAnimationView *)voiceView {
    if (!_voiceView) {
        _voiceView = [[FGVoiceAnimationView alloc] init];
        __weak typeof(self) weakSelf = self;
        _voiceView.timeoutEndRecordBlock = ^{
            [weakSelf voiceFinished];
        };
    }
    return _voiceView;
}

/// 屏幕将要旋转
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    /// 可正确获取到安全区域
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        [self.keyboardView configLayout:size];
        [self.noticeView resetSize:size];
    } completion:nil];
}

/// What
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
    if ([[UIApplication sharedApplication] statusBarFrame].size.height > 20) { // 判断是否为iPhoneX及以上机型
        return UIRectEdgeNone;
    }
    return UIRectEdgeBottom;
}

#pragma mark - UIGestureRecognizerDelegate

// 手势代理，解决和tableview点击发生的冲突
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // 判断如果点击的是tableView的cell或者是collectionView的cell，就把手势给关闭了
    if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"] ||
        [touch.view.superview isKindOfClass:UICollectionViewCell.class]) {
        return NO;
    }
    return YES;
}

@end
